package edu.jxufe.nb112.blog.core.persist.service;

import edu.jxufe.nb112.common.code.exception.ExceptionCodeConstant;
import edu.jxufe.nb112.common.code.exception.ServiceException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializer;

import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.Set;

/**
 * Created by lvxi on 2018/2/25.
 * Note:
 */
public class CacheServiceImpl<K,V> implements edu.jxufe.nb112.common.code.cache.CacheService {

    private static final Logger LOG = LoggerFactory.getLogger(CacheServiceImpl.class.getName());

    @Autowired
    CacheManager cacheManager;

    /**
     * 获取缓存
     * @param cacheName
     * @return
     */
    public Cache getCache(String cacheName) {
        return cacheManager.getCache(cacheName);
    }

    /**
     * 获取缓存
     *
     * @param cacheName
     * @param key
     * @return
     */
    public Object get(String cacheName, Object key) {
        Cache.ValueWrapper valueWrapper = getCache(cacheName).get(key);
        if(valueWrapper!=null) {
            return valueWrapper.get();
        }
        return  null;
    }

    /**
     * 清除缓存
     * @param cacheName 缓存名称
     * @param key 主键
     */
    public void evict(String cacheName, Object key) {
        Cache cache = getCache(cacheName);
        cache.evict(cacheName+":"+key);
    }

    /**
     * 清空缓存
     * @param cacheName
     */
    public void clear(String cacheName) {
        Cache cache = getCache(cacheName);
        cache.clear();
    }

    /**
     * 获取缓存数量
     *
     * @param cacheName
     * @return
     */
    public int size(final String cacheName) {
        if (LOG.isDebugEnabled()) {
            LOG.debug("获取{}缓存数量",cacheName);
        }
        Cache cache = getCache(cacheName);
        if(cache!=null){
            Object nativeCache = cache.getNativeCache();
            if(nativeCache instanceof RedisTemplate) {
                final RedisTemplate<K, V> redisTemplate = (RedisTemplate<K, V>) nativeCache;
                return redisTemplate.execute(new RedisCallback<Integer>() {
                    public Integer doInRedis(RedisConnection connection) throws DataAccessException {
                        RedisSerializer redisSerializer = redisTemplate.getKeySerializer();
                        Set<byte[]> keys = connection.keys(redisSerializer.serialize(cacheName + ":*"));
                        return keys.size();
                    }
                });
            }else {
                throw new ServiceException(ExceptionCodeConstant.DEFAULT,cacheName+"缓存不是redis");
            }
        }else {
            throw new ServiceException(ExceptionCodeConstant.DEFAULT,"没有"+cacheName+"缓存");
        }

    }

    /**
     * 获取所有key
     *
     * @param cacheName
     * @return
     */
    public Set<K> keys(final String cacheName) {

        if (LOG.isDebugEnabled()) {
            LOG.debug("获取{}缓存所有主键keys",cacheName);
        }
        Cache cache = getCache(cacheName);
        if(cache!=null){
            Object nativeCache = cache.getNativeCache();
            if(nativeCache instanceof RedisTemplate) {
                final RedisTemplate<K, V> redisTemplate = (RedisTemplate<K, V>) nativeCache;
                return redisTemplate.execute(new RedisCallback<Set<K>>() {
                    public Set<K> doInRedis(RedisConnection connection) throws DataAccessException {
                        RedisSerializer redisSerializer = redisTemplate.getKeySerializer();
                        Set<byte[]> keys = connection.keys(redisSerializer.serialize(cacheName + ":*"));
                        Set<K> cacheKeys = new LinkedHashSet<K>();
                        if (!org.springframework.util.CollectionUtils.isEmpty(keys)) {
                            for (byte[] key : keys) {
                                K keyStr = ((RedisSerializer<K>)redisTemplate.getKeySerializer()).deserialize(key);
                                cacheKeys.add(keyStr);
                            }
                        }
                        return cacheKeys;
                    }
                });
            }else {
                throw new ServiceException(ExceptionCodeConstant.DEFAULT,cacheName+"缓存不是redis");
            }
        }else {
            throw new ServiceException(ExceptionCodeConstant.DEFAULT,"没有"+cacheName+"缓存");
        }
    }

    /**
     * 获取所有值
     *
     * @param cacheName
     * @return
     */
    public Collection<V> values(final String cacheName) {
        if (LOG.isDebugEnabled()) {
            LOG.debug("获取{}缓存所有主键keys",cacheName);
        }
        Cache cache = getCache(cacheName);
        if(cache!=null){
            Object nativeCache = cache.getNativeCache();
            if(nativeCache instanceof RedisTemplate) {
                final RedisTemplate<K, V> redisTemplate = (RedisTemplate<K, V>) nativeCache;
                return redisTemplate.execute(new RedisCallback<Collection<V>>() {
                    public Collection<V> doInRedis(RedisConnection connection) throws DataAccessException {
                        RedisSerializer redisKeySerializer = redisTemplate.getKeySerializer();
                        RedisSerializer<V> redisValueSerializer = (RedisSerializer<V>) redisTemplate.getValueSerializer();
                        Set<byte[]> keys = connection.keys(redisKeySerializer.serialize(cacheName + ":*"));
                        Collection<V> cacheValues= new ArrayList<V>();
                        if (!org.springframework.util.CollectionUtils.isEmpty(keys)) {
                            for (byte[] key : keys) {
                                byte[] valueByte = connection.get(key);
                                if(valueByte!=null){
                                    Object value =  redisValueSerializer.deserialize(valueByte);
                                    cacheValues.add((V) value);
                                }
                            }
                        }
                        return cacheValues;
                    }
                });
            }else {
                throw new ServiceException(ExceptionCodeConstant.DEFAULT,cacheName+"缓存不是redis");
            }
        }else {
            throw new ServiceException(ExceptionCodeConstant.DEFAULT,"没有"+cacheName+"缓存");
        }
    }


}
